#!/sw/bin/perl -w


use strict;

use threads;
use IO::Socket;

use IO::File;
use File::Path;

use Cwd;
use YAML;


my $exec_path = cwd();
my $logs_paht = $exec_path . "/../logs";
my $conf_path = $exec_path . "/../data";

my @server_refs = YAML::LoadFile( $conf_path . "/config.yaml" );

my %server_threads;
my %channel_threads;
my %channel_mutex;
my %channel_shared_string;

my %send_mutex;
my %update_mutex;
my %update_string;
my %updater;


threads::share( %send_mutex );
threads::share( %update_mutex );
threads::share( %update_string );
threads::share( %updater );

threads::share( %channel_mutex );
threads::share( %channel_shared_string );


sub server_connect;
sub server_listen;
sub channel_connect;
sub channel_watch;
sub raw_socket_parser;


sub server_connect {
  
  my $ref       = shift               || warn "No data passed to \&server_connect\n";
  my $host      = $ref->{ host }      || warn "No host name provided for current server\n";
  my $port      = $ref->{ port }      || 6667;
  my $nick      = $ref->{ nick }      || getlogin;
  my $ident     = $ref->{ ident }     || "msqirc/usr";
  my $real_name = $ref->{ real_name } || getlogin;
  
  
  $ref->{ socket } = new IO::Socket::INET (
                                           PeerAddr => $host,
                                           PeerPort => $port,
                                           Proto    => 'tcp'
                                          ) or warn "Could not create socket to $host\n";
  
  my $socket = $ref->{ socket };
  
  print $socket "NICK $nick \r\n";
  print $socket ":$nick USER $ident $host bla :$real_name\r\n";
  
  &{ $updater{ hlist_add }}( $host );
  &{ $updater{ tab_construct }}( $host );
  
  $send_mutex{ $host } = 1;
  $update_mutex{ $host } = 1;
  $update_string{ $houst } = "";
}


sub server_listen {
  
  my $ref = shift             || warn "No data passed to \&server_listen\n";
  my $host = $ref->{ host }   || warn "No host name provided for this server\n";
  my $sock = $ref->{ socket } || warn "Not connected to server $host\n";
  
  my $channel_updater = shift;
  
  while( my $line = <$sock> ) {
    $line =~ s/^\s*(\S*(?:\s+\S+)*)\s*$/$1/g;
    if( $line =~ m/^PING(.+)/ ) {
      print $sock "PONG $1\r\n";
    }
    elsif ( m/^:([^!]+!~[^@]+\@[^ ]+|[^ ]+) ([A-Z]+|\d+) (.+)$/ ) {
      &event_handler( $ref, $1, $2, $3 );
    }
    else {
      warn "Unknown input from server: $host\n";
    }
  }
}


sub channel_connect {
  
  my $ref      = shift             || warn "No data passed to \&channel_connect\n";
  my $host     = $ref->{ host }    || warn "No host name provided for this channel\n";
  my $sock     = $ref->{ socket }  || warn "Not connected to server $host\n";
  my $nick     = $ref->{ nick }    || warn "You should really never see this\n";
  my $channel  = shift             || warn "No channel provided to \&channel_connect\n";
  
  print $sock  ":$nick JOIN $channel\r\n";
  
  &{ $updater{ hlist_add }}( "$host-$channel" );
  &{ $updater{ tab_construct }}( "$host-$channel" );
  
  $send_mutex{ "$host-$channel" } = 1;
  $update_mutex{ "$host-$channel" } = 1;
  $update_string{ "$host-$channel" } = "";
  
}


sub generate_logfile {
  
  my $ref = shift           || warn "No data passed - creating dummy log file\n";
  my $channel = shift       || "SERVER_LOG";
  my $host = $ref->{ host } || warn "No host for this log\n";
  
  my $file_location = $log_path;
  
  $file_location . "/" . $host    if $host;
  $file_location . "/" . $channel if $channel;
  
  mkpath( $file_location );
  
  my ( $s, $m, $h, $day, $mon, $year, $w, $y, $i) = localtime( time );  
  my $file_name = ($year + 1900) . "-$mon-$day";
  
  return new IO::File( "$file_location/$file_name", "a" );
}


sub event_handler {
  my ($ref, $who, $command, $message) = @_;
  
  my ($nick, $ident, $host_mask) = split( /!~|@/, $who, 3 );
  
  my $host = $ref->{ host } || warn "No data passed\n";
  
  if ( $command =~ 
  
  
}




#  # Sever operations - command passing
# sub msg_send_pass {
#   #    Command: PASS
#   # Parameters: <password>
# }

# sub msg_send_nick {
#   #    Command: NICK
#   # Parameters: <nickname> [ <hopcount> ]
# }

# sub msg_send_user {
#   #    Command: USER
#   # Parameters: <username> <hostname> <servername> <realname>
# }

# sub msg_send_server {
#   #    Command: SERVER
#   # Parameters: <servername> <hopcount> <info>
# }

# sub msg_send_oper {
#   #    Command: OPER
#   # Parameters: <user> <password>
# }

# sub msg_send_quit {
#   #    Command: QUIT
#   # Parameters: [<Quit message>]
# }

# sub msg_send_squit {
#   #    Command: SQUIT
#   # Parameters: <server> <comment>
# }



# # Channel Operations
# sub msg_send_join {
#   #    Command: JOIN
#   # Parameters: <channel>{,<channel>} [<key>{,<key>}]
#   my $ref      = shift                   || die "No data passed\n";
#   my $sock     = $ref->{ socket }        || die "No socket for this server\n";
#   my $nick     = $ref->{ nick }          || die "You should never see this\n";
#   my $channels = $ref->{ channels }      || die "No channels for this server\n";

#   for my $channel ( @$channels ) {
#     print Dumper( $channel );
#     print STDOUT ":$nick JOIN $channel\n";
#     print $sock  ":$nick JOIN $channel\r\n";
#   }
# }

# sub msg_send_part {
#   #    Command: PART
#   # Parameters: <channel>{,<channel>}
# }

# sub msg_send_mode {
#   #    Command: MODE
#   # Parameters: <channel> {[+|-]|o|p|s|i|t|n|b|v} [<limit>] [<user>] [<ban mask>]
#   # Parameters: <nickname> {[+|-]|i|w|s|o}
#   #    The various modes available for channels are as follows:
#   #       o - give/take channel operator privileges;
#   #       p - private channel flag;
#   #       s - secret channel flag;
#   #       i - invite-only channel flag;
#   #       t - topic settable by channel operator only flag;
#   #       n - no messages to channel from clients on the outside;
#   #       m - moderated channel;
#   #       l - set the user limit to channel;
#   #       b - set a ban mask to keep users out;
#   #       v - give/take the ability to speak on a moderated channel;
#   #       k - set a channel key (password).
#   #    The available modes are as follows:
#   #       i - marks a users as invisible;
#   #       s - marks a user for receipt of server notices;
#   #       w - user receives wallops;
#   #       o - operator flag
# }

# sub msg_send_topic {
#   #    Command: TOPIC
#   # Parameters: <channel> [<topic>]
# }

# sub msg_send_names {
#   #    Command: NAMES
#   # Parameters: [<channel>{,<channel>}]
# }

# sub msg_send_list {
#   #    Command: LIST
#   # Parameters: [<channel>{,<channel>} [<server>]]
# }

# sub msg_send_invite {
#   #    Command: INVITE
#   # Parameters: <nickname> <channel>
# }

# sub msg_send_kick {
#   #    Command: KICK
#   # Parameters: <channel> <user> [<comment>]
# }


# # Server Queries and Commands
# #    Command: VERSION
# # Parameters: [<server>]
# #    Command: STATS
# # Parameters: [<query> [<server>]]
# #    The currently supported queries are:
# #       c - returns a list of servers which the server may connect to or allow connections from;
# #       h - returns a list of servers which are either forced to be treated as leaves or allowed to act as hubs;
# #       i - returns a list of hosts which the server allows a client to connect from;
# #       k - returns a list of banned username/hostname combinations for that server;
# #       l - returns a list of the server's connections, showing how long each connection has been established and the traffic over that connection in bytes and messages for each direction;
# #       m - returns a list of commands supported by the server and the usage count for each if the usage count is non zero;
# #       o - returns a list of hosts from which normal clients may become operators;
# #       y - show Y (Class) lines from server's configuration file;
# #       u - returns a string showing how long the server has been up.
# #    Command: LINKS
# # Parameters: [[<remote server>] <server mask>]
# #    Command: TIME
# # Parameters: [<server>]
# #    Command: CONNECT
# # Parameters: <target server> [<port> [<remote server>]]
# #    Command: TRACE
# # Parameters: [<server>]
# #    Command: ADMIN
# # Parameters: [<server>]
# #    Command: INFO
# # Parameters: [<server>]

# # Private Messags
# #    Command: PRIVMSG
# # Parameters: <receiver>{,<receiver>} <text to be sent>
# #    Command: NOTICE
# # Parameters: <nickname> <text>

# # Who Query
# #    Command: WHO
# # Parameters: [<name> [<o>]]
# #    Command: WHOIS
# # Parameters: [<server>] <nickmask>[,<nickmask>[,...]]
# #    Command: WHOWAS
# # Parameters: <nickname> [<count> [<server>]]

# # Kill Message
# #    Command: KILL
# # Parameters: <nickname> <comment>

# # Ping Message
# #    Command: PING
# # Parameters: <server1> [<server2>]

# # Pong Message
# #    Command: PONG
# # Parameters: <daemon> [<daemon2>]

# # Error Message
# #    Command: ERROR
# # Parameters: <error message>

# #Optional Commnads
# #   Command:	AWAY
# #Parameters:	[message]
# #   Command:	REHASH
# #Parameters:	None
# #   Command:	RESTART
# #Parameters:	None
# #   Command:	SUMMON
# #Parameters:	<user> [<server>]
# #   Command:	USERS
# #Parameters:	[<server>]
# #   Command:	WALLOPS
# #Parameters:	Text to be sent to all operators currently online
